package org.codehaus.activemq.management;

import javax.jms.Message;
import javax.management.j2ee.statistics.CountStatistic;
import javax.management.j2ee.statistics.JMSEndpointStats;
import javax.management.j2ee.statistics.TimeStatistic;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.activemq.util.IndentPrinter;

public class JMSEndpointStatsImpl extends StatsImpl
  implements JMSEndpointStats
{
  private static final Log log = LogFactory.getLog(JMSEndpointStatsImpl.class);
  protected CountStatisticImpl messageCount;
  protected CountStatisticImpl pendingMessageCount;
  protected CountStatisticImpl expiredMessageCount;
  protected TimeStatistic messageWaitTime;
  protected TimeStatisticImpl messageRateTime;

  public JMSEndpointStatsImpl(JMSSessionStatsImpl sessionStats)
  {
    this();
    setParent(this.messageCount, sessionStats.getMessageCount());
    setParent(this.pendingMessageCount, sessionStats.getPendingMessageCount());
    setParent(this.expiredMessageCount, sessionStats.getExpiredMessageCount());
    setParent(this.messageWaitTime, sessionStats.getMessageWaitTime());
    setParent(this.messageRateTime, sessionStats.getMessageRateTime());
  }

  protected void setParent(CountStatistic child, CountStatistic parent) {
    if (((child instanceof CountStatisticImpl)) && ((parent instanceof CountStatisticImpl))) {
      CountStatisticImpl c = (CountStatisticImpl)child;
      c.setParent((CountStatisticImpl)parent);
    }
    else {
      log.warn("Cannot associate endpoint counters with session level counters as they are not both CountStatisticImpl clases. Endpoint: " + child + " session: " + parent);
    }
  }

  protected void setParent(TimeStatistic child, TimeStatistic parent) {
    if (((child instanceof TimeStatisticImpl)) && ((parent instanceof TimeStatisticImpl))) {
      TimeStatisticImpl c = (TimeStatisticImpl)child;
      c.setParent((TimeStatisticImpl)parent);
    }
    else {
      log.warn("Cannot associate endpoint counters with session level counters as they are not both TimeStatisticImpl clases. Endpoint: " + child + " session: " + parent);
    }
  }

  public JMSEndpointStatsImpl()
  {
    this(new CountStatisticImpl("messageCount", "Number of messages processed"), new CountStatisticImpl("pendingMessageCount", "Number of pending messages"), new CountStatisticImpl("expiredMessageCount", "Number of expired messages"), new TimeStatisticImpl("messageWaitTime", "Time spent by a message before being delivered"), new TimeStatisticImpl("messageRateTime", "Time taken to process a message (thoughtput rate)"));
  }

  public JMSEndpointStatsImpl(CountStatisticImpl messageCount, CountStatisticImpl pendingMessageCount, CountStatisticImpl expiredMessageCount, TimeStatisticImpl messageWaitTime, TimeStatisticImpl messageRateTime)
  {
    this.messageCount = messageCount;
    this.pendingMessageCount = pendingMessageCount;
    this.expiredMessageCount = expiredMessageCount;
    this.messageWaitTime = messageWaitTime;
    this.messageRateTime = messageRateTime;

    addStatistic("messageCount", messageCount);
    addStatistic("pendingMessageCount", pendingMessageCount);
    addStatistic("expiredMessageCount", expiredMessageCount);
    addStatistic("messageWaitTime", messageWaitTime);
    addStatistic("messageRateTime", messageRateTime);
  }

  public CountStatistic getMessageCount() {
    return this.messageCount;
  }

  public CountStatistic getPendingMessageCount() {
    return this.pendingMessageCount;
  }

  public CountStatistic getExpiredMessageCount() {
    return this.expiredMessageCount;
  }

  public TimeStatistic getMessageWaitTime() {
    return this.messageWaitTime;
  }

  public String toString() {
    StringBuffer buffer = new StringBuffer();
    buffer.append(this.messageCount);
    buffer.append(" ");
    buffer.append(this.messageRateTime);
    buffer.append(" ");
    buffer.append(this.pendingMessageCount);
    buffer.append(" ");
    buffer.append(this.expiredMessageCount);
    buffer.append(" ");
    buffer.append(this.messageWaitTime);
    return buffer.toString();
  }

  public void onMessage(Message message) {
    long start = this.messageCount.getLastSampleTime();
    this.messageCount.increment();
    long end = this.messageCount.getLastSampleTime();
    this.messageRateTime.addTime(end - start);
  }

  public void dump(IndentPrinter out) {
    out.printIndent();
    out.println(this.messageCount);
    out.printIndent();
    out.println(this.messageRateTime);
    out.printIndent();
    out.println(this.pendingMessageCount);
    out.printIndent();
    out.println(this.messageRateTime);
    out.printIndent();
    out.println(this.expiredMessageCount);
    out.printIndent();
    out.println(this.messageWaitTime);
  }
}